﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using PortalCurriculo.Domain.Utils;

namespace PortalCurriculo.MvcWebUI.Models
{
    public class ModelBase
        {
            public const string FormatoData = "dd/MM/yyyy";
            public int Id { get; set; }
            public bool Ativo { get; set; }
            public bool UsuarioEstaLogado;
        }

        public class ModelBase<T, TEntity> : ModelBase
            where T : new()
            where TEntity : GeneralAction, new()
        {
            public TEntity CriarDominio(TEntity dominio = default(TEntity))
            {
                if (dominio == null)
                    dominio = new TEntity();

                foreach (var property in dominio.GetType().GetProperties().Where(p => !p.Name.Contains("Key") && !p.Name.EndsWith("Reference")))
                {
                    var propertyModel = typeof(T).GetProperty(property.Name);

                    if (propertyModel == null) continue;

                    var valor = propertyModel.GetValue(this, null);

                    if (property.PropertyType.Namespace.Contains("Domain"))
                    {
                        if (valor == null) continue;

                        var method = propertyModel.PropertyType.GetMethod("CriarDominio");

                        if (method.IsGenericMethodDefinition)
                        {
                            var methodGeneric =
                                propertyModel.PropertyType.GetMethod("CriarDominio").MakeGenericMethod(new[] { property.PropertyType });
                            valor = methodGeneric.Invoke(valor, new[] { property.GetValue(dominio, null) });
                        }
                        else
                            valor = method.Invoke(valor, new[] { property.GetValue(dominio, null) });
                    }

                    property.SetValue(dominio, valor, null);
                }

                return dominio;
            }

            public IEnumerable<T> CriarViewModel(IEnumerable<EntityObject> dominio)
            {
                return dominio.Select(CriarViewModel).ToList();
            }

            public T CriarViewModel(EntityObject dominio)
            {
                if (dominio == null) return default(T);

                var model = new T();

                foreach (var property in model.GetType().GetProperties())
                {
                    try
                    {
                        var propertyDominio = dominio.GetType().GetProperty(property.Name);
                        if (propertyDominio == null) continue;

                        var valorDominio = propertyDominio.GetValue(dominio, null);
                        if (valorDominio == null) continue;

                        if (valorDominio.GetType().Namespace.Contains("Domain"))
                        {
                            var method = property.PropertyType.GetMethod("CriarViewModel", new[] { typeof(EntityObject) });
                            var retornoMetodo = method.Invoke(Activator.CreateInstance(property.PropertyType),
                                                              new[] { propertyDominio.GetValue(dominio, null) });
                            property.SetValue(model, retornoMetodo, null);
                        }
                        else if (valorDominio.GetType().FullName.Contains("EntityCollection"))
                        {
                            var listTipo = property.PropertyType.FullName.Split(new[] { '[', ']', ',' }, StringSplitOptions.RemoveEmptyEntries);
                            var tipo = Activator.CreateInstance(listTipo[2], listTipo[1]).Unwrap();
                            var method = tipo.GetType().GetMethod("CriarViewModel", new[] { typeof(List<EntityObject>) });
                            var retornoMetodo = method.Invoke(tipo, new[] { propertyDominio.GetValue(dominio, null) });
                            property.SetValue(model, retornoMetodo, null);
                        }
                        else
                            property.SetValue(model, propertyDominio.GetValue(dominio, null), null);
                    }
                    catch
                    {
                        continue;
                    }
                }

                return model;
            }

            public static T Converter(FormCollection collection)
            {
                var dominio = Activator.CreateInstance(typeof(T));

                foreach (string key in collection.Keys)
                {
                    var propriedade = dominio.GetType().GetProperty(key);

                    try
                    {
                        if (propriedade != null)
                        {
                            if (propriedade.PropertyType == typeof(Decimal) ||
                                propriedade.PropertyType == typeof(decimal))
                                propriedade.SetValue(dominio, Decimal.Parse(collection[key]), null);
                            else if (propriedade.PropertyType == typeof(Boolean) ||
                                     propriedade.PropertyType == typeof(bool))
                                propriedade.SetValue(dominio, Boolean.Parse(collection[key].Split(',').First()), null);
                            else if (propriedade.PropertyType == typeof(Int16) ||
                                     propriedade.PropertyType == typeof(Int32) ||
                                     propriedade.PropertyType == typeof(Int64) ||
                                     propriedade.PropertyType == typeof(uint) ||
                                     propriedade.PropertyType == typeof(UInt16) ||
                                     propriedade.PropertyType == typeof(UInt32) ||
                                     propriedade.PropertyType == typeof(UInt64) ||
                                    propriedade.PropertyType == typeof(int?))
                                propriedade.SetValue(dominio, int.Parse(collection[key]), null);
                            else if (propriedade.PropertyType == typeof(DateTime))
                                propriedade.SetValue(dominio, DateTime.Parse(collection[key]), null);
                            else if (propriedade.PropertyType == typeof(char))
                                propriedade.SetValue(dominio, char.Parse(collection[key]), null);
                            else
                                propriedade.SetValue(dominio, collection[key], null);
                        }
                    }
                    catch
                    {
                    }
                }

                return (T)dominio;
            }

            public string GetParameterValue(string url, string paramName)
            {
                var uri = new Uri(url);
                if (!string.IsNullOrEmpty(uri.Query) && uri.Query.ToLower().Contains(paramName))
                {
                    Match m = Regex.Match(uri.Query, "^?" + paramName + "=([^&#]*)");
                    if (m.Success) return m.Value.Replace(paramName + "=", string.Empty);
                }
                return string.Empty;
            }
        }
}